#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <pthread.h>
#include <netinet/in.h>
#include <sys/time.h> // for settimeofday, though not used directly here
 
#define MULTICAST_ADDR "239.255.255.250"
#define MULTICAST_PORT 12345
#define BUFFER_SIZE 1024
 
void* send_multicast_message(void* arg) {
    int sockfd = *((int*)arg);
    const char* message = "Hello, Multicast!";
    struct sockaddr_in multicast_addr;
 
    memset(&multicast_addr, 0, sizeof(multicast_addr));
    multicast_addr.sin_family = AF_INET;
    multicast_addr.sin_port = htons(MULTICAST_PORT);
    inet_pton(AF_INET, MULTICAST_ADDR, &multicast_addr.sin_addr);
 
    while (1) {
        sendto(sockfd, message, strlen(message), 0,
               (struct sockaddr*)&multicast_addr, sizeof(multicast_addr));
        printf("Sent: %s\n", message);
        sleep(1);
    }
    return NULL;
}
 
void* receive_multicast_message(void* arg) {
    int sockfd = *((int*)arg);
    char buffer[BUFFER_SIZE];
    struct sockaddr_in src_addr;
    socklen_t addr_len = sizeof(src_addr);
 
    while (1) {
        int num_bytes = recvfrom(sockfd, buffer, BUFFER_SIZE, 0,
                                 (struct sockaddr*)&src_addr, &addr_len);
        if (num_bytes > 0) {
            buffer[num_bytes] = '\0';
            printf("Received from %s: %s\n", inet_ntoa(src_addr.sin_addr), buffer);
        }
    }
    return NULL;
}
 
int main() {
    int sockfd;
    struct sockaddr_in local_addr;
    pthread_t sender_thread, receiver_thread;
 
    // 创建UDP套接字
    if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket creation failed");
        exit(EXIT_FAILURE);
    }
 
    int allow = 1;
    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
                   &allow, sizeof(allow)) < 0) {
        perror("setsockopt");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
 
    // 绑定套接字到本地地址和端口（可选，但推荐）
    memset(&local_addr, 0, sizeof(local_addr));
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    local_addr.sin_port = htons(MULTICAST_PORT);
 
    if (bind(sockfd, (const struct sockaddr*)&local_addr, sizeof(local_addr)) < 0) {
        perror("bind failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
 
    // 允许接收组播消息
    struct ip_mreq mreq;
    mreq.imr_multiaddr.s_addr = inet_addr(MULTICAST_ADDR);
    mreq.imr_interface.s_addr = htonl(INADDR_ANY);
 
    if (setsockopt(sockfd, IPPROTO_IP, IP_ADD_MEMBERSHIP, (char*)&mreq, sizeof(mreq)) < 0) {
        perror("setsockopt");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
 
    // 启动发送和接收线程
    if (pthread_create(&sender_thread, NULL, send_multicast_message, &sockfd) != 0) {
        perror("pthread_create sender failed");
        close(sockfd);
        exit(EXIT_FAILURE);
    }
 
    if (pthread_create(&receiver_thread, NULL, receive_multicast_message, &sockfd) != 0) {
        perror("pthread_create receiver failed");
        close(sockfd);
        pthread_cancel(sender_thread); // 尝试取消已创建的发送线程
        exit(EXIT_FAILURE);
    }
 
    // 注意：在纯C中，我们通常不会在这里等待线程完成，因为它们是无限循环的。
    // 如果需要终止程序，应该使用某种信号或全局变量来控制线程的退出。
    // 这里为了示例，我们让主线程也无限等待（不推荐在实际应用中使用）。
    // 通常，你会在另一个线程或信号处理程序中设置某个条件来优雅地关闭所有线程。
 
    // 无限等待（不推荐）
     while (1) sleep(1);
 
    // 正确的方式是使用某种机制来通知主线程可以安全地关闭套接字和退出程序。
 
    // 由于示例的简化性质，这里我们不会实现这样的机制。
 
    // 注意：在实际应用中，不要忘记在程序退出前清理资源，包括取消线程和关闭套接字。
 
    // 示例代码结束，这里不会真正退出程序。
 
    // 清理代码（在实际应用中需要实现）：
    // pthread_cancel(sender_thread);
    // pthread_cancel(receiver_thread);
    // pthread_join(sender_thread, NULL);
    // pthread_join(receiver_thread, NULL);
    // close(sockfd);
 
    return 0; // 这行代码在实际应用中不会被执行，因为上面有一个无限循环。
}